"""
酶抑制剂清除率计算模块

该模块实现了在酶抑制剂存在下的药物清除率计算，包括四种可逆性抑制模式：
- 竞争性抑制 (Competitive inhibition)
- 非竞争性抑制 (Noncompetitive inhibition)  
- 反竞争性抑制 (Uncompetitive inhibition)
- 混合型抑制 (Mixed type inhibition)

参考标准酶抑制动力学公式，基于Michaelis-Menten方程推导

作者：BlackCat@CPPO
版本：1.0.0
"""

import numpy as np
from typing import Dict, Any, Union
from enum import Enum

class Inhibition_Model(Enum):
    """酶抑制作用类型枚举"""
    COMPETITIVE_INHIBITION = "Competitive inhibition"        # 可逆性抑制中竞争性抑制
    UNCOMPETITIVE_INHIBITION = "Uncompetitive inhibition"    # 可逆性抑制中反竞争性抑制
    NONCOMPETITIVE_INHIBITION = "Noncompetitive inhibition"  # 可逆性抑制中非竞争性抑制
    MIXED_TYPE_INHIBITION = "Mixed type inhibition"          # 可逆性抑制中混合竞争性抑制


class InhibitionClearanceCalculator:
    """
    酶抑制剂清除率计算器
    
    该类计算在酶抑制剂存在下的药物清除率变化，支持四种抑制模式
    """
    
    def __init__(self, parameters: Dict[str, Any]):
        """
        初始化抑制剂清除率计算器
        
        参数:
            parameters (dict): 模型参数，包含：
                - Vmax: 最大反应速率 (μmol/min/mg蛋白)
                - Km: 米氏常数 (μM)
                - Clint: 内在清除率 (L/h/kg)
                - liver_weight: 肝脏重量 (kg)
                - microsomal_protein: 微粒体蛋白浓度 (mg/g肝脏)
                - fu: 游离分数
                - BP: 血液-血浆浓度比
                - inhibitor_concentration: 抑制剂浓度 (μM)
                - Ki: 抑制常数 (μM)
                - alpha: 混合型抑制参数 (用于混合型抑制)
                - beta: 混合型抑制参数 (用于混合型抑制)
        """
        self.params = parameters
        self.validate_parameters()
    
    def validate_parameters(self):
        """验证模型参数的有效性"""
        required_params = ['Vmax', 'Km', 'Clint', 'fu', 'BP']
        for param in required_params:
            if param not in self.params:
                raise ValueError(f"缺少必需参数：{param}")
    
    def calculate_competitive_inhibition_clearance(self, 
                                                 substrate_concentration: Union[float, np.ndarray],
                                                 inhibitor_concentration: Union[float, np.ndarray] = None) -> Dict[str, Any]:
        """
        计算竞争性抑制下的清除率
        
        竞争性抑制公式：
        V_inhibited = Vmax / (Km * (1 + [I]/Ki) + [S]) * (1 / fu_mic)
        
        参数:
            substrate_concentration: 底物浓度 (μM)
            inhibitor_concentration: 抑制剂浓度 (μM)，如为None则使用self.params中的值
            
        返回:
            dict: 包含抑制后清除率的计算结果
        """
        # 获取参数
        Vmax = self.params['Vmax']
        Km = self.params['Km']
        Ki = self.params.get('Ki', 1.0)
        Clint = self.params['Clint']
        fu = self.params['fu']
        fu_mic = self.params.get('fu_mic', 1.0)
        
        if inhibitor_concentration is None:
            inhibitor_concentration = self.params.get('inhibitor_concentration', 0.0)
            
        # 将输入转换为numpy数组
        substrate_concentration = np.atleast_1d(substrate_concentration)
        inhibitor_concentration = np.atleast_1d(inhibitor_concentration)
        
        # 计算抑制倍数
        inhibition_factor = 1 + inhibitor_concentration / Ki
        
        # 计算抑制后的最大反应速率
        Vmax_inhibited = Vmax / inhibition_factor
        
        # 计算抑制后的内在清除率
        Clint_inhibited = Clint / inhibition_factor
        
        # 计算抑制后的Km值
        Km_inhibited = Km * inhibition_factor
        
        # 计算抑制后的反应速率
        correct_rate = 1 / fu_mic
        reaction_rate = Vmax / (Km * inhibition_factor + substrate_concentration) * correct_rate
        
        # 计算肝脏清除率（well-stirred模型）
        liver_weight = self.params.get('liver_weight', 1.8)  # kg
        microsomal_protein = self.params.get('microsomal_protein', 45.0)  # mg/g肝脏
        liver_blood_flow = self.params.get('liver_flow', 1.35)  # L/h
        
        # 计算内在清除率（L/h）
        intrinsic_clearance = Clint_inhibited * microsomal_protein * liver_weight / 1000
        
        # 计算肝脏清除率
        hepatic_clearance = (liver_blood_flow * fu * intrinsic_clearance) / (
            liver_blood_flow + fu * intrinsic_clearance)
        
        # 计算抑制比例
        inhibition_ratio = 1 - (hepatic_clearance / 
                               self.calculate_control_clearance(substrate_concentration)['hepatic_clearance'])
        
        return {
            'inhibition_mode': 'competitive',
            'inhibitor_concentration': inhibitor_concentration,
            'inhibition_factor': inhibition_factor,
            'Vmax_inhibited': Vmax_inhibited,
            'Km_inhibited': Km_inhibited,
            'Clint_inhibited': Clint_inhibited,
            'hepatic_clearance': hepatic_clearance,
            'inhibition_ratio': inhibition_ratio,
            'reaction_rate': reaction_rate,
            'Ki': Ki
        }
    
    def calculate_noncompetitive_inhibition_clearance(self, 
                                                    substrate_concentration: Union[float, np.ndarray],
                                                    inhibitor_concentration: Union[float, np.ndarray] = None) -> Dict[str, Any]:
        """
        计算非竞争性抑制下的清除率
        
        非竞争性抑制公式：
        V_inhibited = Vmax / ((Km + [S]) * (1 + [I]/Ki)) * (1 / fu_mic)
        
        参数:
            substrate_concentration: 底物浓度 (μM)
            inhibitor_concentration: 抑制剂浓度 (μM)
            
        返回:
            dict: 包含抑制后清除率的计算结果
        """
        # 获取参数
        Vmax = self.params['Vmax']
        Km = self.params['Km']
        Ki = self.params.get('Ki', 1.0)
        Clint = self.params['Clint']
        fu = self.params['fu']
        fu_mic = self.params.get('fu_mic', 1.0)
        
        if inhibitor_concentration is None:
            inhibitor_concentration = self.params.get('inhibitor_concentration', 0.0)
            
        # 将输入转换为numpy数组
        substrate_concentration = np.atleast_1d(substrate_concentration)
        inhibitor_concentration = np.atleast_1d(inhibitor_concentration)
        
        # 计算抑制倍数
        inhibition_factor = 1 + inhibitor_concentration / Ki
        
        # 计算抑制后的最大反应速率
        Vmax_inhibited = Vmax / inhibition_factor
        
        # 计算抑制后的内在清除率
        Clint_inhibited = Clint / inhibition_factor
        
        # Km值不变
        Km_inhibited = Km
        
        # 计算抑制后的反应速率
        correct_rate = 1 / fu_mic
        reaction_rate = Vmax / ((Km + substrate_concentration) * inhibition_factor) * correct_rate
        
        # 计算肝脏清除率
        liver_weight = self.params.get('liver_weight', 1.8)  # kg
        microsomal_protein = self.params.get('microsomal_protein', 45.0)  # mg/g肝脏
        liver_blood_flow = self.params.get('liver_flow', 1.35)  # L/h
        
        intrinsic_clearance = Clint_inhibited * microsomal_protein * liver_weight / 1000
        hepatic_clearance = (liver_blood_flow * fu * intrinsic_clearance) / (
            liver_blood_flow + fu * intrinsic_clearance)
        
        # 计算抑制比例
        inhibition_ratio = 1 - (hepatic_clearance / 
                               self.calculate_control_clearance(substrate_concentration)['hepatic_clearance'])
        
        return {
            'inhibition_mode': 'noncompetitive',
            'inhibitor_concentration': inhibitor_concentration,
            'inhibition_factor': inhibition_factor,
            'Vmax_inhibited': Vmax_inhibited,
            'Km_inhibited': Km_inhibited,
            'Clint_inhibited': Clint_inhibited,
            'hepatic_clearance': hepatic_clearance,
            'inhibition_ratio': inhibition_ratio,
            'reaction_rate': reaction_rate,
            'Ki': Ki
        }
    
    def calculate_uncompetitive_inhibition_clearance(self, 
                                                   substrate_concentration: Union[float, np.ndarray],
                                                   inhibitor_concentration: Union[float, np.ndarray] = None) -> Dict[str, Any]:
        """
        计算反竞争性抑制下的清除率
        
        反竞争性抑制公式：
        V_inhibited = Vmax / (Km + [S] * (1 + [I]/Ki)) * (1 / fu_mic)
        
        参数:
            substrate_concentration: 底物浓度 (μM)
            inhibitor_concentration: 抑制剂浓度 (μM)
            
        返回:
            dict: 包含抑制后清除率的计算结果
        """
        # 获取参数
        Vmax = self.params['Vmax']
        Km = self.params['Km']
        Ki = self.params.get('Ki', 1.0)
        Clint = self.params['Clint']
        fu = self.params['fu']
        fu_mic = self.params.get('fu_mic', 1.0)
        
        if inhibitor_concentration is None:
            inhibitor_concentration = self.params.get('inhibitor_concentration', 0.0)
            
        # 将输入转换为numpy数组
        substrate_concentration = np.atleast_1d(substrate_concentration)
        inhibitor_concentration = np.atleast_1d(inhibitor_concentration)
        
        # 计算抑制倍数
        inhibition_factor = 1 + inhibitor_concentration / Ki
        
        # 计算抑制后的最大反应速率
        Vmax_inhibited = Vmax / inhibition_factor
        
        # 计算抑制后的内在清除率
        Clint_inhibited = Clint / inhibition_factor
        
        # 计算抑制后的Km值
        Km_inhibited = Km / inhibition_factor
        
        # 计算抑制后的反应速率
        correct_rate = 1 / fu_mic
        reaction_rate = Vmax / (Km + substrate_concentration * inhibition_factor) * correct_rate
        
        # 计算肝脏清除率
        liver_weight = self.params.get('liver_weight', 1.8)  # kg
        microsomal_protein = self.params.get('microsomal_protein', 45.0)  # mg/g肝脏
        liver_blood_flow = self.params.get('liver_flow', 1.35)  # L/h
        
        intrinsic_clearance = Clint_inhibited * microsomal_protein * liver_weight / 1000
        hepatic_clearance = (liver_blood_flow * fu * intrinsic_clearance) / (
            liver_blood_flow + fu * intrinsic_clearance)
        
        # 计算抑制比例
        inhibition_ratio = 1 - (hepatic_clearance / 
                               self.calculate_control_clearance(substrate_concentration)['hepatic_clearance'])
        
        return {
            'inhibition_mode': 'uncompetitive',
            'inhibitor_concentration': inhibitor_concentration,
            'inhibition_factor': inhibition_factor,
            'Vmax_inhibited': Vmax_inhibited,
            'Km_inhibited': Km_inhibited,
            'Clint_inhibited': Clint_inhibited,
            'hepatic_clearance': hepatic_clearance,
            'inhibition_ratio': inhibition_ratio,
            'reaction_rate': reaction_rate,
            'Ki': Ki
        }
    
    def calculate_mixed_inhibition_clearance(self, 
                                           substrate_concentration: Union[float, np.ndarray],
                                           inhibitor_concentration: Union[float, np.ndarray] = None) -> Dict[str, Any]:
        """
        计算混合型抑制下的清除率
        
        混合型抑制公式：
        V_inhibited = Vmax / (Km * (1 + [I]/Ki) + [S] * (1 + [I]/(α*Ki)) * (1 / fu_mic)
        
        参数:
            substrate_concentration: 底物浓度 (μM)
            inhibitor_concentration: 抑制剂浓度 (μM)
            
        返回:
            dict: 包含抑制后清除率的计算结果
        """
        # 获取参数
        Vmax = self.params['Vmax']
        Km = self.params['Km']
        Ki = self.params.get('Ki', 1.0)
        alpha = self.params.get('alpha', 1.0)  # 混合型抑制参数
        beta = self.params.get('beta', 1.0)   # 混合型抑制参数
        Clint = self.params['Clint']
        fu = self.params['fu']
        fu_mic = self.params.get('fu_mic', 1.0)
        
        if inhibitor_concentration is None:
            inhibitor_concentration = self.params.get('inhibitor_concentration', 0.0)
            
        # 将输入转换为numpy数组
        substrate_concentration = np.atleast_1d(substrate_concentration)
        inhibitor_concentration = np.atleast_1d(inhibitor_concentration)
        
        # 计算抑制因子
        alpha_factor = 1 + inhibitor_concentration / (alpha * Ki)
        beta_factor = 1 + inhibitor_concentration / Ki
        
        # 计算抑制后的最大反应速率
        Vmax_inhibited = Vmax / alpha_factor
        
        # 计算抑制后的内在清除率
        Clint_inhibited = Clint * (Vmax_inhibited / Vmax) * (Km / (Km * beta_factor / alpha_factor))
        
        # 计算抑制后的Km值
        Km_inhibited = Km * beta_factor / alpha_factor
        
        # 计算抑制后的反应速率
        correct_rate = 1 / fu_mic
        reaction_rate = Vmax / (Km * beta_factor + substrate_concentration * alpha_factor) * correct_rate
        
        # 计算肝脏清除率
        liver_weight = self.params.get('liver_weight', 1.8)  # kg
        microsomal_protein = self.params.get('microsomal_protein', 45.0)  # mg/g肝脏
        liver_blood_flow = self.params.get('liver_flow', 1.35)  # L/h
        
        intrinsic_clearance = Clint_inhibited * microsomal_protein * liver_weight / 1000
        hepatic_clearance = (liver_blood_flow * fu * intrinsic_clearance) / (
            liver_blood_flow + fu * intrinsic_clearance)
        
        # 计算抑制比例
        inhibition_ratio = 1 - (hepatic_clearance / 
                               self.calculate_control_clearance(substrate_concentration)['hepatic_clearance'])
        
        return {
            'inhibition_mode': 'mixed',
            'inhibitor_concentration': inhibitor_concentration,
            'alpha_factor': alpha_factor,
            'beta_factor': beta_factor,
            'Vmax_inhibited': Vmax_inhibited,
            'Km_inhibited': Km_inhibited,
            'Clint_inhibited': Clint_inhibited,
            'hepatic_clearance': hepatic_clearance,
            'inhibition_ratio': inhibition_ratio,
            'reaction_rate': reaction_rate,
            'Ki': Ki,
            'alpha': alpha,
            'beta': beta
        }
    
    def calculate_control_clearance(self, substrate_concentration: Union[float, np.ndarray]) -> Dict[str, Any]:
        """
        计算无抑制剂情况下的对照清除率
        
        参数:
            substrate_concentration: 底物浓度 (μM)
            
        返回:
            dict: 包含对照清除率的计算结果
        """
        # 获取参数
        Vmax = self.params['Vmax']
        Km = self.params['Km']
        Clint = self.params['Clint']
        fu = self.params['fu']
        fu_mic = self.params.get('fu_mic', 1.0)
        
        # 将输入转换为numpy数组
        substrate_concentration = np.atleast_1d(substrate_concentration)
        
        # 计算反应速率
        correct_rate = 1 / fu_mic
        reaction_rate = Vmax * substrate_concentration / (Km + substrate_concentration) * correct_rate
        
        # 计算肝脏清除率
        liver_weight = self.params.get('liver_weight', 1.8)  # kg
        microsomal_protein = self.params.get('microsomal_protein', 45.0)  # mg/g肝脏
        liver_blood_flow = self.params.get('liver_flow', 1.35)  # L/h
        
        intrinsic_clearance = Clint * microsomal_protein * liver_weight / 1000
        hepatic_clearance = (liver_blood_flow * fu * intrinsic_clearance) / (
            liver_blood_flow + fu * intrinsic_clearance)
        
        return {
            'inhibition_mode': 'control',
            'Vmax': Vmax,
            'Km': Km,
            'Clint': Clint,
            'hepatic_clearance': hepatic_clearance,
            'reaction_rate': reaction_rate
        }
    
    def calculate_all_inhibition_modes(self, 
                                     substrate_concentration: Union[float, np.ndarray],
                                     inhibitor_concentration: Union[float, np.ndarray] = None) -> Dict[str, Any]:
        """
        计算所有四种抑制模式下的清除率
        
        参数:
            substrate_concentration: 底物浓度 (μM)
            inhibitor_concentration: 抑制剂浓度 (μM)
            
        返回:
            dict: 包含所有抑制模式的计算结果
        """
        # 计算对照组
        control_result = self.calculate_control_clearance(substrate_concentration)
        
        # 计算各抑制模式
        competitive_result = self.calculate_competitive_inhibition_clearance(
            substrate_concentration, inhibitor_concentration)
        noncompetitive_result = self.calculate_noncompetitive_inhibition_clearance(
            substrate_concentration, inhibitor_concentration)
        uncompetitive_result = self.calculate_uncompetitive_inhibition_clearance(
            substrate_concentration, inhibitor_concentration)
        mixed_result = self.calculate_mixed_inhibition_clearance(
            substrate_concentration, inhibitor_concentration)
        
        return {
            'control': control_result,
            'competitive': competitive_result,
            'noncompetitive': noncompetitive_result,
            'uncompetitive': uncompetitive_result,
            'mixed': mixed_result,
            'summary': {
                'substrate_concentration': substrate_concentration,
                'inhibitor_concentration': inhibitor_concentration,
                'inhibition_ratios': {
                    'competitive': competitive_result['inhibition_ratio'],
                    'noncompetitive': noncompetitive_result['inhibition_ratio'],
                    'uncompetitive': uncompetitive_result['inhibition_ratio'],
                    'mixed': mixed_result['inhibition_ratio']
                },
                'clearance_values': {
                    'control': control_result['hepatic_clearance'],
                    'competitive': competitive_result['hepatic_clearance'],
                    'noncompetitive': noncompetitive_result['hepatic_clearance'],
                    'uncompetitive': uncompetitive_result['hepatic_clearance'],
                    'mixed': mixed_result['hepatic_clearance']
                }
            }
        }


class InhibitionModelIntegrator:
    """
    抑制剂模型集成器
    
    该类用于将抑制剂清除率计算集成到现有的PBPK模型中
    """
    
    def __init__(self, elimination_model):
        """
        初始化抑制剂集成器
        
        参数:
            elimination_model: 现有的消除模型实例
        """
        self.elimination_model = elimination_model
        
    def apply_inhibition_to_clearance(self, 
                                    inhibition_mode: Inhibition_Model,
                                    parameters: Dict[str, Any],
                                    substrate_concentration: Union[float, np.ndarray],
                                    inhibitor_concentration: Union[float, np.ndarray] = None) -> Dict[str, Any]:
        """
        将抑制剂效应应用到清除率计算
        
        参数:
            inhibition_mode: 抑制模式
            parameters: 模型参数
            substrate_concentration: 底物浓度
            inhibitor_concentration: 抑制剂浓度
            
        返回:
            dict: 包含抑制后清除率的计算结果
        """
        # 创建抑制剂计算器
        inhibition_calculator = InhibitionClearanceCalculator(parameters)
        
        # 根据抑制模式选择计算方法
        if inhibition_mode == Inhibition_Model.COMPETITIVE_INHIBITION:
            result = inhibition_calculator.calculate_competitive_inhibition_clearance(
                substrate_concentration, inhibitor_concentration)
        elif inhibition_mode == Inhibition_Model.NONCOMPETITIVE_INHIBITION:
            result = inhibition_calculator.calculate_noncompetitive_inhibition_clearance(
                substrate_concentration, inhibitor_concentration)
        elif inhibition_mode == Inhibition_Model.UNCOMPETITIVE_INHIBITION:
            result = inhibition_calculator.calculate_uncompetitive_inhibition_clearance(
                substrate_concentration, inhibitor_concentration)
        elif inhibition_mode == Inhibition_Model.MIXED_TYPE_INHIBITION:
            result = inhibition_calculator.calculate_mixed_inhibition_clearance(
                substrate_concentration, inhibitor_concentration)
        else:
            raise ValueError(f"不支持的抑制模式: {inhibition_mode}")
        
        return result